package main;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class ProcesProcessor {

	private ArrayList<Proces> procesy = new ArrayList<Proces>();
	private ArrayList<ArrayList<Integer>> historia = new ArrayList<ArrayList<Integer>>();
	private Double koniecPracy;
	public static final Double JEDNOSTKA_CZASU = (double) 1;

	public ProcesProcessor(Double p_koniecPracy) {
		this.koniecPracy = p_koniecPracy;

	}

	public void dodajProces(Double p_dlugos, Double p_okres) {
		procesy.add(new Proces(p_dlugos, p_okres));

	}

	public void ustawPiorytety() {

		int max = procesy.size();

		Collections.sort(procesy, new Comparator<Object>() {

			public int compare(Object o1, Object o2) {
				Proces p1 = (Proces) o1;
				Proces p2 = (Proces) o2;
				return p1.getOkres().compareTo(p2.getOkres());
			}

		});
		Iterator<Proces> itr = procesy.iterator();
		while (itr.hasNext()) {
			itr.next().setPiorytet(max--);
		}

	}

	public void symulacjaRMS() {
		czyscProcesy();
		stworzHistorie();
		for (Double i = new Double(0); i < this.koniecPracy; i = i
				+ JEDNOSTKA_CZASU) {
			Iterator<Proces> itr = procesy.iterator();
			boolean ustawionoPrace = false;
			while (itr.hasNext()) {
				Proces proces = itr.next();
				if (proces.getDlugoscCzekania() > 0) {
					proces.czekaj();
				} else {
					if (!ustawionoPrace) {
						proces.dodajPrace();
						ustawionoPrace = true;
					} else {
						if (proces.getStan() == proces.PROCES_PRACUJE
								|| proces.getStan() == proces.PROCES_USPIONY) {
							proces.uspijPrace();
						} else {
							proces.czekaj();
						}
					}
				}
			}
			zapiszStan();
		}
		wypiszProcesy();
		wypiszHistorie();

	}
	
	public int[][] getProcessesStates(){
		
		int [][] processesTab = new int[historia.size()][koniecPracy.intValue()];
		
		Iterator<ArrayList<Integer>> itr = this.historia.iterator();
		int i=0,j=0;
		while (itr.hasNext()) {
			ArrayList<Integer> proces = itr.next();
			Iterator<Integer> itrproces = proces.iterator();
			while (itrproces.hasNext()) {
				processesTab[i][j] = itrproces.next().intValue();
				
				j++;
			}
			i++;
			j=0;

		}
		
		return processesTab;
	}
	
	public void clearHistory(){
		this.historia.clear();
	}

	private void wypiszHistorie() {
		Iterator<ArrayList<Integer>> itr = this.historia.iterator();
		while (itr.hasNext()) {
			ArrayList<Integer> proces = itr.next();
			Iterator<Integer> itrproces = proces.iterator();
			while (itrproces.hasNext()) {
				System.out.print(itrproces.next());
			}
			System.out.println();

		}

	}

	private void stworzHistorie() {
		for (int i = 0; i < this.procesy.size(); i++) {
			this.historia.add(new ArrayList<Integer>());
		}
	}

	public void zapiszStan() {
		int i = 0;
		Iterator it = sortProces().entrySet().iterator();

		while (it.hasNext()) {
			Map.Entry pairs = (Map.Entry) it.next();
			this.historia.get(i++).add(((Proces) pairs.getValue()).getStan());

		}

	}

	private Map sortProces() {
		Iterator<Proces> itrProcesy = this.procesy.iterator();
		Map map = new HashMap<Integer,Proces>();
		while (itrProcesy.hasNext()) {
			Proces proces = itrProcesy.next();
			map.put(proces.getId(), proces);
		}
		return map;
	}

	public void wypiszProcesy() {
		Iterator<Proces> itr = this.procesy.iterator();
		while (itr.hasNext()) {
			Proces proces = itr.next();
			System.out.println("id:" + proces.getId() + " "
					+ proces.getDlugosc() + " " + proces.getOkres());
		}
	}

	public void symulacjaEDF() {
		czyscProcesy();
		stworzHistorie();
		wypiszProcesy();
		for (Double i = new Double(0); i < this.koniecPracy; i = i
				+ JEDNOSTKA_CZASU) {
			Proces procesAktualny = znajdzProcesZPierwszymZakonczeniem();
			if (procesAktualny == null) {
				wszystkieCzekaja();
			} else {
				Integer id = procesAktualny.getId();
				Iterator<Proces> itr = procesy.iterator();

				while (itr.hasNext()) {
					Proces proces = itr.next();
					if (id.equals(proces.getId())) {
						proces.dodajPraceEDF();
					} else {
						Integer stan = proces.getStan();
						if (stan == proces.PROCES_PRACUJE
								&& proces.getOkres().compareTo(
										proces.getDlugoscCzekania()) == 0) {
							proces.czekaj();
						} else {
							if (stan == proces.PROCES_USPIONY
									|| stan == proces.PROCES_PRACUJE) {
								proces.uspijPrace();
							}
							if (stan == proces.PROCES_NICNIEROBI) {
								proces.czekaj();
							}

						}
					}
				}
			}

			zapiszStan();
			//wypiszProcesy();
			//wypiszHistorie();
		}
		wypiszProcesy();
		wypiszHistorie();

	}

	private void czyscProcesy() {
		Iterator<Proces>itr=this.procesy.iterator();
		while(itr.hasNext()){
			itr.next().czysc();
		}
	}

	private void wszystkieCzekaja() {
		Iterator<Proces> itr = this.procesy.iterator();
		while (itr.hasNext()) {
			itr.next().czekaj();

		}
	}

	private Proces znajdzProcesZPierwszymZakonczeniem() {
		ArrayList<Proces> localProcesy = procesy;

		localProcesy = getDostepneProcesy(localProcesy);
		Iterator<Proces> itr = localProcesy.iterator();
		Double min = new Double(100000);
		Integer id = null;
		while (itr.hasNext()) {
			Proces proces = itr.next();
			Double temp = null;

			if (proces.getStan().equals(Proces.PROCES_PRACUJE)) {
				temp = proces.getDlugosc() - proces.getWykonanaPraca();
				if (proces.getWykonanaPraca().equals(new Double(0))) {
					temp = proces.getDlugosc() + proces.getOkres();
				}
			}
			if (proces.getStan().equals(Proces.PROCES_NICNIEROBI)) {
				if (proces.getDlugoscCzekania().compareTo(new Double(0)) == -1) {
					temp = proces.getDlugosc();
				} else {
					temp = proces.getDlugoscCzekania() + proces.getDlugosc();
				}
			}
			if (proces.getStan().equals(Proces.PROCES_USPIONY)) {
				temp = proces.getDlugosc() - proces.getWykonanaPraca();
			}

			if (temp.compareTo(min) == -1) {
				min = temp;
				id = proces.getId();
			}

		}
		if (id != null) {
			itr = localProcesy.iterator();
			while (itr.hasNext()) {
				Proces proces = itr.next();
				if (id.equals(proces.getId())) {
					return proces;
				}

			}
		}
		return null;
	}

	private ArrayList<Proces> getDostepneProcesy(
			ArrayList<Proces> p_localProcesy) {
		ArrayList<Proces> result = new ArrayList<Proces>();
		Iterator<Proces> itr = p_localProcesy.iterator();
		while (itr.hasNext()) {
			Proces proc = itr.next();
			if (proc.getDlugoscCzekania().compareTo(new Double(0)) <= 0) {
				result.add(proc);
			}
		}
		return result;
	}

	public void clearId() {
		Proces.ID_MAIN=0;
		
	}

}
